package com.sunsharing.flow.exe;

import com.sunsharing.common.Context;
import com.sunsharing.common.anno.AnoClassCretator;
import com.sunsharing.common.utils.IOUtils;
import com.sunsharing.common.utils.StringUtils;
import com.sunsharing.flow.eventman.EventManager;
import com.sunsharing.flow.model.Node;
import com.sunsharing.flow.model.ProcessDefinition;
import com.sunsharing.flow.model.Transition;
import com.sunsharing.flow.model.node.*;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: criss
 * Date: 13-5-5
 * Time: 下午3:53
 * To change this template use File | Settings | File Templates.
 */
public class WorkFlowService {
    static Logger logger = Logger.getLogger(WorkFlowService.class);
    static ProcessDefinition pd = null;
    static Map<String,ProcessDefinition> pdMap = new HashMap<String, ProcessDefinition>();

    public static ProcessDefinition getFlow(String name)
    {
        return pdMap.get(name);
    }
    static ScriptEngineManager mgr = new ScriptEngineManager();
    static ScriptEngine engine = mgr.getEngineByName("JavaScript");
    public static String evalStr(String a) throws Exception
    {
        return (String)engine.eval(a);
    }
    public static  void loadFlows()
    {
        try
        {
            String path = StringUtils.getClassPath();
            File temp = new File(path+"flow");
            File[] fs = temp.listFiles();
            if(fs!=null)
            {
                for(File f:fs)
                {
                    String xml = IOUtils.readContent(f);
                    Document doc = DocumentHelper.parseText(xml);
                    Element root = doc.getRootElement();
                    String output = root.attributeValue("output");
                    String flowName = root.attributeValue("name");
                    ProcessDefinition pd = new ProcessDefinition();
                    pd.setId(flowName);
                    pd.setOutput(output);

                    List<Element> nods = root.element("Nodes").elements();
                    List<Node> nodeList = new ArrayList<Node>();
                    for(Element n:nods)
                    {
                        Node no = (Node) AnoClassCretator.getInstance().
                                createObject(Node.class,n.getName());
                        no.setId(n.attributeValue("id"));
                        no.setName(no.getId());
                        nodeList.add(no);
                        pd.addNode(no);
                        if(no instanceof TaskNode)
                        {
                            TaskNode tskNode = (TaskNode)no;
                            List<Element> calls =  n.elements("Call");
                            for(Element eleCall:calls)
                            {
                                Call call = (Call)AnoClassCretator.getInstance().createObject(Call.class,
                                        eleCall.attributeValue("type"));
                                call.setId(eleCall.attributeValue("id"));
                                call.setType(eleCall.attributeValue("type"));
                                call.setOutput(eleCall.attributeValue("output"));
                                if(call.getType().equals("java"))
                                {
                                    ((JavaCall)call).setCls(eleCall.attributeValue("class"));
                                    ((JavaCall)call).setMethod(eleCall.attributeValue("method"));
                                    ((JavaCall)call).initMethod();
                                }
                                if(call.getType().equals("webservice"))
                                {
                                    ((WebServiceCall)call).setServiceName(eleCall.attributeValue("name"));
                                }
                                tskNode.setCall(call);
                            }
                        }
                        if(no instanceof OrFork)
                        {
                            OrFork tskNode = (OrFork)no;
                            tskNode.setExpresstion(n.attributeValue("expresstion"));
                        }

                    }

                    List<Element> trs = root.element("Transitions").elements("Transition");
                    for(Element tr:trs)
                    {
                        Transition ts = new Transition();
                        ts.setId(tr.attributeValue("id"));
                        ts.setName(ts.getId());
                        Node fromNode = findeNodeById(tr.attributeValue("fromNode"),nodeList);
                        Node toNode = findeNodeById(tr.attributeValue("toNode"),nodeList);
                        ts.setFromNode(fromNode);
                        ts.setToNode(toNode);
                        ts.setExpression(tr.attributeValue("expresstion"));
                        fromNode.addLeavingTransition(ts);
                        toNode.addArrivingTransition(ts);
                    }

                    pdMap.put(pd.getId(),pd);
                }
            }

        }catch (Exception e)
        {
            logger.error("加载流程失败",e);
            throw new RuntimeException("加载流程失败");
        }
    }
    private static Node findeNodeById(String id,List<Node> n)
    {
        for(Node t:n)
        {
            if(t.getId().equals(id))
            {
                return t;
            }
        }
        return null;
    }
    public static ProcessInstance createFlowInstance(ProcessDefinition definition,Context context)
    {
        ProcessInstance pi = new ProcessInstance(definition,context);
        return pi;
    }
    public static ProcessInstance createTestInstance(Context context)
    {
        if(pd==null)
        {
            StartNode startNode = new StartNode();
            startNode.setName("开始节点");
            EndNode endNode = new EndNode();
            endNode.setName("结束节点");
            TaskNode taskNode = new TaskNode();
            taskNode.setName("任务节点");
            Transition t1 = new Transition();
            t1.setFromNode(startNode);
            t1.setToNode(taskNode);
            startNode.addLeavingTransition(t1);
            taskNode.addArrivingTransition(t1);

            Transition t2 = new Transition();
            t2.setFromNode(taskNode);
            t2.setToNode(endNode);

            endNode.addArrivingTransition(t2);
            taskNode.addLeavingTransition(t2);

            pd = new ProcessDefinition();
            pd.addNode(startNode);
            pd.addNode(endNode);
            pd.addNode(taskNode);



        }

        ProcessInstance instans = WorkFlowService.createFlowInstance(pd,context);
        return instans;
    }
}
